﻿using Itech_Run.Sys.Application.Contracts.Dto;
using Itech_Run.Sys.Application.Contracts.Service;
using Itech_Run.Sys.Domain.Entity;
using System.Linq.Expressions;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using abp = Volo.Abp.Specifications;
using System.Linq.Dynamic.Core;
using Itech_Run.Sys.Domain.Manager;
using Itech_Run.Application.Shared;
using Itech_Run.Domain.Shared.Exception;
using Itech_Run.Domain.Shared.Const;
using Itech_Run.Sys.Domain.IRepository;
using Volo.Abp.Application.Dtos;
using Itech_Run.Application.Contracts.Shared.Dto;

namespace Itech_Run.Sys.Application.Service
{
    public class SysUserService : BaseApplicationService<Sys_User>, ISysUserService
    {
        private readonly IRepository<Sys_User, string> _sysUserRepository;
        private readonly Sys_UserManager _sysUserManager;
        private readonly ISys_UserRepository _sysUserRepositorySpecify;

        public SysUserService(IRepository<Sys_User, string> sysUserRepository, Sys_UserManager sysUserManager, ISys_UserRepository sysUserRepositorySpecify)
        {
            _sysUserRepository = sysUserRepository;
            _sysUserManager = sysUserManager;
            _sysUserRepositorySpecify = sysUserRepositorySpecify;
        }

        public async Task<SysUserDto> GetAsync(string id)
        {
            var sysUser = await _sysUserRepository.GetAsync(id, includeDetails: true);
            return ObjectMapper.Map<Sys_User, SysUserDto>(sysUser);
        }

        public async Task<List<KeyValueDto>> GetListAsync()
        {
            var query =
                from r in await _sysUserRepository.GetQueryableAsync()
                orderby r.Nickname ascending
                select new KeyValueDto
                {
                    Key = r.Id,
                    Value = r.Nickname
                };

            return query.ToList();
        }

        public async Task<List<KeyValueDto>> GetListAsync(params string[] ids)
        {
            var query =
                from r in await _sysUserRepository.GetQueryableAsync()
                where ids.Contains(r.Id)
                orderby r.Nickname ascending
                select new KeyValueDto
                {
                    Key = r.Id,
                    Value = r.Nickname
                };

            return query.ToList();
        }
        public async Task<PagedResultDto<SysUserDto>> GetListAsync(SysUserListDto listDto)
        {
            if (string.IsNullOrEmpty(listDto.Sorting)) listDto.Sorting = "Sort asc";
            Expression<Func<Sys_User, bool>> curExpression = s => true;
            if (!string.IsNullOrEmpty(listDto.UserName))
                curExpression = curExpression.And(s => s.UserName.Contains(listDto.UserName));
            if (!string.IsNullOrEmpty(listDto.Name))
                curExpression = curExpression.And(s => s.Name.Contains(listDto.Name));
            if (!string.IsNullOrEmpty(listDto.Nickname))
                curExpression = curExpression.And(s => s.Nickname.Contains(listDto.Nickname));
            if (!string.IsNullOrEmpty(listDto.MobileNo))
                curExpression = curExpression.And(s => s.MobileNo.Contains(listDto.MobileNo));
            if (!string.IsNullOrEmpty(listDto.Email))
                curExpression = curExpression.And(s => s.Email.Contains(listDto.Email));
            if (listDto.IsActive != null)
                curExpression = curExpression.And(s => s.IsActive == listDto.IsActive);
            if (!string.IsNullOrEmpty(listDto.RoleId))
                curExpression = curExpression.And(s => s.Sys_UserRole.Any(r => r.RoleId == listDto.RoleId));

            var query = (await _sysUserRepository.WithDetailsAsync()).WhereIf(true, curExpression).OrderBy(listDto.Sorting);
            var items = ObjectMapper.Map<List<Sys_User>, List<SysUserDto>>(query.PageBy(listDto.SkipCount, listDto.MaxResultCount).ToList());

            return new PagedResultDto<SysUserDto>(query.Count(), items);
        }

        public async Task<SysUserDto> InsertAsync(SysUserCreateDto dto, string operateUser)
        {
            var sysUser = ObjectMapper.Map<SysUserCreateDto, Sys_User>(dto);
            await _sysUserManager.Check_UniqueAsync(sysUser);
            SetInsertBy(sysUser, operateUser);
            if (dto.RoleList.Count > 0)
                sysUser.AllocateUserRole(dto.RoleList);
            var result = await _sysUserRepository.InsertAsync(sysUser);
            return ObjectMapper.Map<Sys_User, SysUserDto>(result);
        }

        public async Task<SysUserDto> UpdateAsync(SysUserUpdateDto dto, string operateUser)
        {
            var sysUser = await _sysUserRepository.GetAsync(dto.Id, includeDetails: true);
            ObjectMapper.Map(dto, sysUser);
            await _sysUserManager.Check_UniqueAsync(sysUser);
            SetUpdateBy(sysUser, operateUser);
            sysUser.AllocateUserRole(dto.RoleList);
            var result = await _sysUserRepository.UpdateAsync(sysUser);
            return ObjectMapper.Map<Sys_User, SysUserDto>(result);
        }

        public async Task DeleteAsync(string id)
        {
            try
            {
                var sysUser = await _sysUserRepository.GetAsync(id, includeDetails: true);
                await _sysUserRepository.DeleteAsync(sysUser);
            }
            catch { }
        }

        public async Task<SysUserDto> LoginAsync(SysUserLoginDto dto)
        {
            var result = (await _sysUserRepository.GetListAsync(p => p.UserName == dto.UserName && p.Password == dto.Password)).FirstOrDefault();
            if (result != null)
                return ObjectMapper.Map<Sys_User, SysUserDto>(result);
            throw new CustomFriendlyException(BackErrorConst.UserAccountPasswordNotMatch, BackLocalizer[BackErrorConst.UserAccountPasswordNotMatch]);
        }

        public async Task ChangePasswordForce(string id, string password, string operateUser)
        {
            var sysUser = (await _sysUserRepository.GetListAsync(p => p.Id == id)).FirstOrDefault();
            if (sysUser != null)
            {
                sysUser.Password = password;
                SetUpdateBy(sysUser, operateUser);

                await _sysUserRepository.UpdateAsync(sysUser);
            }
        }

        public async Task ChangePassword(string userName, string oldPassword, string newPassword, string operateUser)
        {
            var result = await LoginAsync(new SysUserLoginDto { UserName = userName, Password = oldPassword });
            if (result != null)
            {
                await ChangePasswordForce(result.Id, newPassword, operateUser);
            }
        }

        public async Task<string?> GetResume(string operateUser)
        {
            var resume = (await _sysUserRepository.GetAsync(operateUser, includeDetails: true)).Sys_Resume.Content;
            return resume;
        }
    }
}
